package com.ifp.opengate.boot.utils;

import java.io.ByteArrayInputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import net.sf.json.JSON;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.xml.XMLSerializer;

public class Xml2JsonUtil {

    private static final String EBBC = " xmlns:ebbc=\"http://ebbc.com/\"";

    public static String removeXmlNs(String str) {
        try {
            ByteArrayInputStream b = new ByteArrayInputStream(str.getBytes("UTF-8"));
            SAXReader READER = new SAXReader();
            Document doc = READER.read(b);

            // 去除xml文档的命名空间
            Element rootElement = removeElementNs(doc.getRootElement());
            doc.setRootElement(rootElement);

            return doc.asXML();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * xml元素拷贝去除命名空间
     * 
     * @param element
     * @return
     */
    @SuppressWarnings("unchecked")
    public static Element removeElementNs(Element element) {
        String name = element.getName();
        String text = element.getText();

        // name = underline2Camel(name,true);

        Element distElement = DocumentHelper.createElement(name);
        if (text != null) {
            distElement.setText(text.trim());
        }
        List<Attribute> list = element.attributes();
        for (Attribute attr : list) {
            attr.setParent(null);
            String attrName = attr.getName();
            attr.setName(attrName);

            distElement.add(attr);
        }

        List<Element> elist = element.elements();
        for (Element e : elist) {
            Element childElement = removeElementNs(e);
            distElement.add(childElement);
        }
        return distElement;
    }

    public static String xml2Json(String rootName, String xmlStr) {
        try {
            // ByteArrayInputStream bt = new ByteArrayInputStream(xmlStr.getBytes("UTF-8"));

            XMLSerializer xmlSerializer = new XMLSerializer();
            xmlSerializer.setRootName(rootName);
            // 将xml转为json（注：如果是元素的属性，会在json里的key前加一个@标识）
            JSON json = xmlSerializer.read(xmlStr);
            String jsonStr = json.toString();
            jsonStr = JsonDealUtils.getNoNullValue(jsonStr);
            return jsonStr;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String json2Xml(String jsonStr, String rootName, String target) {
        JSONObject jsonobject = JSONObject.fromObject(jsonStr);
        return json2Xml(jsonobject, rootName, target);
    }

    public static String json2Xml(String jsonStr, String systemId) {
        JSONObject jsonobject = JSONObject.fromObject(jsonStr);
        return json2Xml(jsonobject, systemId);
    }

    public static String json2Xml(JSONObject jsonobject, String systemId) {
        String reqXml = null;
        if ("ebbc".equals(systemId)) {
            reqXml = json2EbbcXml(jsonobject);
        }
        if ("ser".equals(systemId)) {
            reqXml = json2SerXml(jsonobject);
        }
        return reqXml;
    }

    public static String json2SerXml(JSONObject jsonobject) {
        StringBuilder sb = new StringBuilder();
        sb.append(
            "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:ser=\"http://service.esb.jbbis.com.cn/\">");
        sb.append("<soap:Header>");
        sb.append("<soaHeader>");
        JSONObject header = JSONObject.fromObject(jsonobject.get("header"));
        jsonToXmlstr(header, sb);
        sb.append("</soaHeader>");
        sb.append("</soap:Header>");
        sb.append("<soap:Body>");
        JSONObject body = JSONObject.fromObject(jsonobject.get("body"));
        sb.append("<ser2:execute xmlns:ser2=\"http://service.foresb.server.ws.jbbis.com.cn/\">");
        body = JSONObject.fromObject(body.get("execute"));
        sb.append("<request>");
        body = JSONObject.fromObject(body.get("request"));
        sb.append("<requestHeader>");
        JSONObject requestHeader = JSONObject.fromObject(body.get("requestHeader"));
        jsonToXmlstr(requestHeader, sb);
        sb.append("</requestHeader>");
        sb.append("<requestBody>");
        sb.append("<reqBusiInfo>");
        sb.append(JSONObject.fromObject(body.get("requestBody")).get("reqBusiInfo"));
        sb.append("</reqBusiInfo>");
        sb.append("</requestBody>");
        sb.append("</request>");
        sb.append("</ser2:execute>");
        sb.append("</soap:Body>");
        sb.append("</soap:Envelope>");
        return sb.toString();
    }

    public static String json2EbbcXml(JSONObject jsonobject) {
        StringBuilder sb = new StringBuilder();
        sb.append("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"");
        sb.append(EBBC);
        sb.append(">");
        sb.append("<soapenv:Header>");
        sb.append("<soaHeader>");
        JSONObject header = JSONObject.fromObject(jsonobject.get("header"));
        jsonToXmlstr(header, sb);
        sb.append("</soaHeader>");
        sb.append("</soapenv:Header>");
        sb.append("<soapenv:Body>");
        JSONObject body = JSONObject.fromObject(jsonobject.get("body"));
        jsonToXmlstr(body, sb, "ebbc:");
        sb.append("</soapenv:Body>");
        sb.append("</soapenv:Envelope>");
        return sb.toString();
    }

    public static String json2Xml(JSONObject jsonobject, String rootName, String target) {
        StringBuilder sb = new StringBuilder();
        if ("ser".equals(target)) {
            sb.append(
                "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:ser=\"http://service.esb.jbbis.com.cn/\">");
        } else {
            sb.append("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"");
            if ("ebbc".equals(target)) {
                sb.append(EBBC);
            }
            sb.append(">");
        }
        sb.append("<soapenv:Header>");
        sb.append("<soaHeader>");
        JSONObject header = JSONObject.fromObject(jsonobject.get("header"));
        jsonToXmlstr(header, sb);
        sb.append("</soaHeader>");
        sb.append("</soapenv:Header>");
        sb.append("<soapenv:Body>");
        JSONObject body = JSONObject.fromObject(jsonobject.get("body"));
        if ("ebbc".equals(target)) {
            jsonToXmlstr(body, sb, "ebbc:");
        } else {
            if ("ser".equals(target)) {
                sb.append("<ser2:execute xmlns:ser2=\"http://service.foresb.server.ws.jbbis.com.cn/\">");
                body = JSONObject.fromObject(body.get("execute"));
            }
            jsonToXmlstr(body, sb);
            if ("ser".equals(target)) {
                sb.append("</ser2:execute>");
            }
        }
        sb.append("</soapenv:Body>");
        sb.append("</soapenv:Envelope>");
        return sb.toString();
    }

    public static String jsonToSocketXml(JSONObject jsonobject, String serviceId) {
        StringBuilder sb = new StringBuilder();
        sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        sb.append("<request>");
        sb.append("<requestHeader>");
        JSONObject header = JSONObject.fromObject(jsonobject.get("header"));
        jsonToXmlstr(header, sb);
        sb.append("</requestHeader>");
        sb.append("<requestBody>");
        JSONObject body = JSONObject.fromObject(jsonobject.get("body"));
        if ("ebbc_pot_qry_0003".equals(serviceId)) {
            jsonToXmlstrWithDataType(body, sb, " type=\"Date\"");
        } else if ("ebap_web_pay_0001".equals(serviceId)) {
            jsonToXmlstrWithDataType(body, sb, "ebap_web_pay_0001.orderDetailList");
        } else {
            jsonToXmlstr(body, sb);
        }

        sb.append("</requestBody>");
        sb.append("</request>");
        return sb.toString();
    }

    public static void main(String[] args) {
        String str =
            "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ebbc=\"http://ebbc.com/\">\r\n"
                + "   <soapenv:Header>\r\n" + "		<soaHeader>\r\n"
                + "			<reqTime>20200701104759</reqTime>\r\n" + "			<appId>app131</appId>\r\n"
                + "			<transId>33600000120200701000000000000031</transId>\r\n"
                + "			<appSign>d7104443484570bd2ea7d1578b39c4e9</appSign>\r\n"
                + "			<hostName></hostName>\r\n" + "			<channelId>314</channelId>\r\n"
                + "			<userRank />\r\n" + "			<originalTransId></originalTransId>\r\n"
                + "			<cacheId />\r\n" + "			<rptContent />\r\n"
                + "			<dataSign>b992c8a1cc76d1e28a432b65b77dfbad</dataSign>\r\n"
                + "			<serviceCode>ebui_oam_aun_0022</serviceCode>\r\n"
                + "			<serviceTarget>ebui</serviceTarget>\r\n"
                + "			<serviceAddress>business/buyAndSell/sendSMSVerCode_v1_0_0_proxy</serviceAddress>\r\n"
                + "			<callbackUri />\r\n"
                + "			<bzTransId>20001100000120200701000000000031</bzTransId>\r\n"
                + "			<requestTime>2020-07-01 10.47.59.763</requestTime>\r\n"
                + "			<reqIP>10.16.45.125</reqIP>\r\n" + "		</soaHeader>\r\n" + "	</soapenv:Header>\r\n"
                + "   <soapenv:Body>\r\n" + "      <ebbc:invoke>\r\n" + "         <!--Optional:-->\r\n"
                + "         <mobile>18612345678</mobile>\r\n" + "         <!--Optional:-->\r\n"
                + "         <openBrc></openBrc>\r\n" + "         <!--Optional:-->\r\n"
                + "         <businessContent></businessContent>\r\n" + "         <!--Optional:-->\r\n"
                + "         <behavCode></behavCode>\r\n" + "      </ebbc:invoke>\r\n" + "   </soapenv:Body>\r\n"
                + "</soapenv:Envelope>";
        str = removeXmlNs(str);
        // System.out.println(str);
        str = xml2Json("request", str);
        System.out.println(str);

        str = json2Xml(JSONObject.fromObject(str), "ebbc");
        System.out.println(str);
    }

    public static String jsonToXmlstr(JSONObject jObj, StringBuilder buffer) {
        Set<Map.Entry<String, Object>> se = jObj.entrySet();
        for (Iterator<Map.Entry<String, Object>> it = se.iterator(); it.hasNext();) {
            Map.Entry<String, Object> en = it.next();
            if (en.getValue().getClass().getName().equals("net.sf.json.JSONObject")) {
                buffer.append("<" + en.getKey() + ">");
                JSONObject jo = jObj.getJSONObject(en.getKey());
                jsonToXmlstr(jo, buffer);
                buffer.append("</" + en.getKey() + ">");
            } else if (en.getValue().getClass().getName().equals("net.sf.json.JSONArray")) {
                JSONArray jarray = jObj.getJSONArray(en.getKey());
                for (int i = 0; i < jarray.size(); i++) {
                    buffer.append("<" + en.getKey() + ">");
                    if (jarray.get(i) instanceof JSONObject) {
                        JSONObject jsonobject = jarray.getJSONObject(i);
                        // System.out.println("jsonobject" + jsonobject + (jsonobject == null));
                        jsonToXmlstr(jsonobject, buffer);
                        buffer.append("</" + en.getKey() + ">");
                    } else {
                        buffer.append(jarray.get(i));
                        buffer.append("</" + en.getKey() + ">");
                    }

                }
            } else if (en.getValue().getClass().getName().equals("java.lang.String")) {
                buffer.append("<" + en.getKey() + ">" + en.getValue());
                buffer.append("</" + en.getKey() + ">");
            }
        }
        return buffer.toString();
    }

    public static String jsonToXmlstrWithDataType(JSONObject jObj, StringBuilder buffer, String dataType) {
        Set<Map.Entry<String, Object>> se = jObj.entrySet();
        for (Iterator<Map.Entry<String, Object>> it = se.iterator(); it.hasNext();) {
            Map.Entry<String, Object> en = it.next();
            if (en.getValue().getClass().getName().equals("net.sf.json.JSONObject")) {
                if ("beginDate".equals(en.getKey()) || "endDate".equals(en.getKey())) {
                    buffer.append("<" + en.getKey() + dataType + ">");
                } else {
                    buffer.append("<" + en.getKey() + ">");
                }

                JSONObject jo = jObj.getJSONObject(en.getKey());
                jsonToXmlstr(jo, buffer, dataType);
                buffer.append("</" + en.getKey() + ">");
            } else if (en.getValue().getClass().getName().equals("net.sf.json.JSONArray")) {
                JSONArray jarray = jObj.getJSONArray(en.getKey());
                for (int i = 0; i < jarray.size(); i++) {
                    buffer.append("<" + en.getKey() + ">");
                    if (jarray.get(i) instanceof JSONObject) {
                        JSONObject jsonobject = jarray.getJSONObject(i);
                        System.out.println("jsonobject" + jsonobject + (jsonobject == null));
                        jsonToXmlstr(jsonobject, buffer, dataType);
                        buffer.append("</" + en.getKey() + ">");
                    } else {
                        buffer.append(jarray.get(i));
                        buffer.append("</" + en.getKey() + ">");
                    }

                }
            } else if (en.getValue().getClass().getName().equals("java.lang.String")) {
                if ("beginDate".equals(en.getKey()) || "endDate".equals(en.getKey())) {
                    buffer.append("<" + en.getKey() + dataType + ">");
                } else {
                    buffer.append("<" + en.getKey() + ">");
                }
                buffer.append(en.getValue());
                buffer.append("</" + en.getKey() + ">");
            }
        }
        return buffer.toString();
    }

    public static String jsonToXmlstr(JSONObject jObj, StringBuilder buffer, String target) {
        if ("ebap_web_pay_0001.orderDetailList".equals(target)) {
            return buffer.append(jObj.toString()).toString();
        }
        Set<Map.Entry<String, Object>> se = jObj.entrySet();
        for (Iterator<Map.Entry<String, Object>> it = se.iterator(); it.hasNext();) {
            Map.Entry<String, Object> en = it.next();
            if (en.getValue().getClass().getName().equals("net.sf.json.JSONObject")) {
                buffer.append("<" + target + en.getKey() + ">");
                JSONObject jo = jObj.getJSONObject(en.getKey());
                jsonToXmlstr(jo, buffer);
                buffer.append("</" + target + en.getKey() + ">");
            } else if (en.getValue().getClass().getName().equals("net.sf.json.JSONArray")) {
                JSONArray jarray = jObj.getJSONArray(en.getKey());
                for (int i = 0; i < jarray.size(); i++) {
                    buffer.append("<" + en.getKey() + ">");
                    if (jarray.get(i) instanceof JSONObject) {
                        JSONObject jsonobject = jarray.getJSONObject(i);
                        System.out.println("jsonobject" + jsonobject + (jsonobject == null));
                        jsonToXmlstr(jsonobject, buffer);
                        buffer.append("</" + en.getKey() + ">");
                    } else {
                        buffer.append(jarray.get(i));
                        buffer.append("</" + en.getKey() + ">");
                    }

                }
            } else if (en.getValue().getClass().getName().equals("java.lang.String")) {
                buffer.append("<" + target + en.getKey() + ">" + en.getValue());
                buffer.append("</" + target + en.getKey() + ">");
            }
        }
        return buffer.toString();
    }

    /*
     * public static String json2Xml(JSON json, String rootName) { XMLSerializer
     * xmlSerializer = new XMLSerializer(); xmlSerializer.setRootName(rootName);
     * 
     * // 不转换属性(json中@符号) xmlSerializer.setTypeHintsEnabled(false);
     * 
     * String xmlStr = xmlSerializer.write(json); return xmlStr; }
     */
    /**
     * 下划线转驼峰法(默认小驼峰)
     * 
     * @param line 源字符串
     * @param smallCamel 大小驼峰,是否为小驼峰(驼峰，第一个字符是大写还是小写)
     * @return 转换后的字符串
     */
    public static String underline2Camel(String line, boolean... smallCamel) {
        if (line == null || "".equals(line)) {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        Pattern pattern = Pattern.compile("([A-Za-z\\d]+)(_)?");
        Matcher matcher = pattern.matcher(line);
        // 匹配正则表达式
        while (matcher.find()) {
            String word = matcher.group();
            // 当是true 或则是空的情况
            if ((smallCamel.length == 0 || smallCamel[0]) && matcher.start() == 0) {
                sb.append(Character.toLowerCase(word.charAt(0)));
            } else {
                sb.append(Character.toUpperCase(word.charAt(0)));
            }

            int index = word.lastIndexOf('_');
            if (index > 0) {
                sb.append(word.substring(1, index).toLowerCase());
            } else {
                sb.append(word.substring(1).toLowerCase());
            }
        }
        return sb.toString();
    }

    /**
     * 驼峰转下划线
     * 
     * @param line
     * @return
     */
    public static String camel2Underline(String line) {
        if (line == null || "".equals(line)) {
            return "";
        }
        line = String.valueOf(line);
        StringBuffer sb = new StringBuffer();
        Pattern pattern = Pattern.compile("[A-Z a-z]([a-z\\d]+)?");
        Matcher matcher = pattern.matcher(line);
        while (matcher.find()) {
            String word = matcher.group();
            sb.append(word);
            System.out.println(word);
            sb.append(matcher.end() == line.length() ? "" : "_");
        }
        return sb.toString();
    }
}
